﻿using System;
using System.ServiceModel;
using System.ServiceModel.Channels;
using Tiscs.Practices.Diagnostics;

namespace Tiscs.Practices.Web.Services.Client
{
    /// <summary>
    /// 身份验证客户端基类。
    /// </summary>
    /// <typeparam name="T">用户信息类的类型。</typeparam>
    public abstract class AuthenticationServiceClientBase<T> : ClientBase<IAuthenticationServiceClient<T>>, IAuthenticationServiceClient<T> where T : UserBase
    {
        /// <summary>
        /// 构造方法。
        /// </summary>
        /// <param name="remoteAddress">身份验证服务地址。</param>
        public AuthenticationServiceClientBase(string remoteAddress)
            : base(CreateBinding(), new EndpointAddress(remoteAddress))
        {
            Exception exception;
            if (!Validation.Parameter<string>(nameof(remoteAddress)).AssertNotNull().CheckRules(remoteAddress, out exception))
            {
                throw exception;
            }
#if SERVER || DESKTOP
            this.Endpoint.Behaviors.Add(new CookieManagerEndpointBehavior());
#endif
#if WINRT
            this.CookieContainer = CookieContainerManager.CookieContainer;
#endif
        }

        /// <summary>
        /// 创建服务绑定。
        /// </summary>
        /// <returns>服务绑定</returns>
        private static Binding CreateBinding()
        {
#if PHONE
            Binding binding = new CustomBinding(new HttpCookieContainerBindingElement(), new BinaryMessageEncodingBindingElement(), new HttpTransportBindingElement() { MaxBufferSize = int.MaxValue, MaxReceivedMessageSize = int.MaxValue });
            return binding;
#elif WINRT
            Binding binding = new CustomBinding(new BinaryMessageEncodingBindingElement(), new HttpTransportBindingElement() { AllowCookies = true, MaxBufferSize = int.MaxValue, MaxReceivedMessageSize = int.MaxValue });
            return binding;
#else
            Binding binding = new CustomBinding(new BinaryMessageEncodingBindingElement(), new HttpTransportBindingElement() { MaxBufferSize = int.MaxValue, MaxReceivedMessageSize = int.MaxValue });
            return binding;
#endif
        }

#if PHONE || WINRT
        #region CookieContainer

        /// <summary>
        /// 获取或设置Cookie容器。
        /// </summary>
        public System.Net.CookieContainer CookieContainer
        {
            get
            {
                System.ServiceModel.Channels.IHttpCookieContainerManager httpCookieContainerManager = this.InnerChannel.GetProperty<System.ServiceModel.Channels.IHttpCookieContainerManager>();
                if ((httpCookieContainerManager != null))
                {
                    return httpCookieContainerManager.CookieContainer;
                }
                else
                {
                    return null;
                }
            }
            set
            {
                System.ServiceModel.Channels.IHttpCookieContainerManager httpCookieContainerManager = this.InnerChannel.GetProperty<System.ServiceModel.Channels.IHttpCookieContainerManager>();
                if ((httpCookieContainerManager != null))
                {
                    httpCookieContainerManager.CookieContainer = value;
                }
                else
                {
                    throw new System.InvalidOperationException("Unable to set the CookieContainer. Please make sure the binding contains an HttpCookieContainerBindingElement.");
                }
            }
        }

        #endregion
#endif

#if PHONE
        #region AuthenticationServiceChannel

        private class AuthenticationServiceClientChannel : ChannelBase<IAuthenticationServiceClient<T>>, IAuthenticationServiceClient<T>
        {
            public AuthenticationServiceClientChannel(ClientBase<IAuthenticationServiceClient<T>> client) :
                base(client)
            {
            }

            public IAsyncResult BeginGetUser(AsyncCallback callback, object state)
            {
                object[] args = new object[0];
                return BeginInvoke(AuthenticationServiceResource.GetUserName, args, callback, state);
            }

            public T EndGetUser(IAsyncResult result)
            {
                object[] args = new object[0];
                return (T)EndInvoke(AuthenticationServiceResource.GetUserName, args, result);
            }

            public IAsyncResult BeginSignIn(string userName, string password, string customCredential, bool isPersistent, AsyncCallback callback, object state)
            {
                object[] args = new object[4] { userName, password, customCredential, isPersistent };
                return base.BeginInvoke(AuthenticationServiceResource.SignInName, args, callback, state);
            }

            T IAuthenticationServiceClient<T>.EndSignIn(IAsyncResult result)
            {
                object[] args = new object[0];
                return (T)EndInvoke(AuthenticationServiceResource.SignInName, args, result);
            }

            public IAsyncResult BeginSignOut(AsyncCallback callback, object state)
            {
                object[] args = new object[0];
                return BeginInvoke(AuthenticationServiceResource.SignOutName, args, callback, state);
            }

            T IAuthenticationServiceClient<T>.EndSignOut(IAsyncResult result)
            {
                object[] args = new object[0];
                return (T)EndInvoke(AuthenticationServiceResource.SignOutName, args, result);
            }

            public IAsyncResult BeginUpdateUser(T user, AsyncCallback callback, object state)
            {
                object[] args = new object[1] { user };
                return BeginInvoke(AuthenticationServiceResource.UpdateUserName, args, callback, state);
            }

            public void EndUpdateUser(IAsyncResult result)
            {
                object[] args = new object[0];
                EndInvoke(AuthenticationServiceResource.UpdateUserName, args, result);
            }
        }

        #endregion

        #region Override CreateChannel

        /// <summary>
        /// 创建身份验证服务客户端信道。
        /// </summary>
        /// <returns>身份验证服务客户端信道。</returns>
        protected override IAuthenticationServiceClient<T> CreateChannel()
        {
            return new AuthenticationServiceClientChannel(this);
        }

        #endregion
#endif

        #region IAuthenticationServiceClient

        /// <summary>
        /// 开始获取用户操作。
        /// </summary>
        /// <param name="callback">异步操作回调。</param>
        /// <param name="state">用户状态。</param>
        /// <returns>异步操作结果。</returns>
        public IAsyncResult BeginGetUser(AsyncCallback callback, object state = null)
        {
            return Channel.BeginGetUser(callback, state);
        }

        /// <summary>
        /// 完成获取用户操作。
        /// </summary>
        /// <param name="result">异步操作结果。</param>
        /// <returns>用户信息实例。</returns>
        public T EndGetUser(IAsyncResult result)
        {
            return Channel.EndGetUser(result);
        }

        /// <summary>
        /// 开始用户登录操作。
        /// </summary>
        /// <param name="userName">用户名。</param>
        /// <param name="password">密码。</param>
        /// <param name="customCredential">自定义凭据。</param>
        /// <param name="isPersistent">是否持久登录。</param>
        /// <param name="callback">异步操作回调。</param>
        /// <param name="state">用户状态。</param>
        /// <returns>异步操作结果。</returns>
        public IAsyncResult BeginSignIn(string userName, string password, string customCredential, bool isPersistent, AsyncCallback callback, object state = null)
        {
            return Channel.BeginSignIn(userName, password, customCredential, isPersistent, callback, state);
        }

        /// <summary>
        /// 完成用户登录操作。
        /// </summary>
        /// <param name="result">异步操作结果。</param>
        /// <returns>用户信息实例。</returns>
        public T EndSignIn(IAsyncResult result)
        {
            return Channel.EndSignIn(result);
        }

        /// <summary>
        /// 开始用户注销操作。
        /// </summary>
        /// <param name="callback">异步操作回调。</param>
        /// <param name="state">用户状态。</param>
        /// <returns>异步操作结果。</returns>
        public IAsyncResult BeginSignOut(AsyncCallback callback, object state = null)
        {
            return Channel.BeginSignOut(callback, state);
        }

        /// <summary>
        /// 完成用户注销操作。
        /// </summary>
        /// <param name="result">异步操作结果。</param>
        /// <returns>用户信息实例。</returns>
        public T EndSignOut(IAsyncResult result)
        {
            return Channel.EndSignOut(result);
        }

        /// <summary>
        /// 开始更新用户操作。
        /// </summary>
        /// <param name="user">用户信息实例。</param>
        /// <param name="callback">异步操作回调。</param>
        /// <param name="state">用户状态。</param>
        /// <returns>异步操作结果。</returns>
        public IAsyncResult BeginUpdateUser(T user, AsyncCallback callback, object state = null)
        {
            return Channel.BeginUpdateUser(user, callback, state);
        }

        /// <summary>
        /// 完成更新用户操作。
        /// </summary>
        /// <param name="result">异步操作结果。</param>
        public void EndUpdateUser(IAsyncResult result)
        {
            Channel.EndUpdateUser(result);
        }

#if SERVER || DESKTOP

        /// <summary>
        /// 获取用户。
        /// </summary>
        /// <returns>用户信息实例。</returns>
        public T GetUser()
        {
            return Channel.GetUser();
        }

        /// <summary>
        /// 用户登录
        /// </summary>
        /// <param name="userName">用户名。</param>
        /// <param name="password">密码。</param>
        /// <param name="customCredential">自定义凭据。</param>
        /// <param name="isPersistent">是否持久登录。</param>
        /// <returns>用户信息实例。</returns>
        public T SignIn(string userName, string password, string customCredential, bool isPersistent)
        {
            return Channel.SignIn(userName, password, customCredential, isPersistent);
        }

        /// <summary>
        /// 注销登录。
        /// </summary>
        /// <returns>用户信息实例。</returns>
        public T SignOut()
        {
            return Channel.SignOut();
        }

        /// <summary>
        /// 更新用户。
        /// </summary>
        /// <param name="user">用户信息实例。</param>
        public void UpdateUser(T user)
        {
            Channel.UpdateUser(user);
        }

#endif

        #endregion
    }
}
